﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class DrawRealize3D
{
    public DrawRealize3D(Transform brush, Transform[] letterArray, GameObject drawMask, GameObject drawMaskParent = null, bool isAddUpdateEvent = true)
    {
        m_Brush = brush;
        m_LetterArray = letterArray;
        m_DrawMask = drawMask;
        m_DrawMaskParent = drawMaskParent;
        bIsAddUpdateEvent = isAddUpdateEvent;
    }

    // 刷子
    private Transform m_Brush;
    
    // 字母笔画的一个数组
    private Transform[] m_LetterArray;

    // 显示层
    private GameObject m_DrawMask;

    // 父级
    private GameObject m_DrawMaskParent;

    // 整条动画的运动时间
    private float m_MoveDuration = 1;

    private float m_MinDis = 1.0f;

    // 新的点跟上一个点的最大间隔距离
    private float m_NewPointMaxDis = 2;

    // 画的时候，左右最大偏移量
    private float m_MaxProjectDis = 2;

    // 多长距离创建一个面片
    private float m_DrawMaskDis = 0.5f;

    // 当前路径索引
    private int m_WayPointIndex = 0;

    // 写的步骤
    private int m_DrawOrder = 0;

    // 笔画的路径数组
    private Vector3[] m_WayPoints;

    private Vector3 m_CurrentPoint;

    private bool bIsDrawing = false;

    // 是否绑定鼠标按钮事件
    private bool bIsAddUpdateEvent = false;

    private Vector3 m_PreviousPoint;

    List<GameObject> m_MaskList = new List<GameObject>();
    List<GameObject> m_DrawList = new List<GameObject>();

    private const string downShader = "Custom/UnlitStencilDown";
    private const string defaultShader = "Unlit/Transparent";
    //private const string upShader = "Custom/UnlitStencilUp";

    private System.Action drawCompleteCallback = null;

    public void OnStart(System.Action callback = null)
    {
        drawCompleteCallback = callback;
        if (bIsAddUpdateEvent)
            EventBus.Instance.AddEventHandler(EventID.ON_MOUSE_BUTTON_HOVER, OnClickHover);
        if (m_Brush == null || m_DrawMask == null || m_LetterArray.Length <= 0)
        {
            Debug.LogError("初始化失败！");
        }
        StartDraw();
    }

    public void OnExit()
    {
        foreach (GameObject go in m_MaskList)
        {
            GameObject.Destroy(go);
        }
        m_MaskList.Clear();

        if (bIsAddUpdateEvent)
            EventBus.Instance.RemoveEventHandler(EventID.ON_MOUSE_BUTTON_HOVER, OnClickHover);
    }

    public void OnUpdate()
    {
        if (Input.GetMouseButton(0))
            OnClickHover();
    }

    private void StartDraw()
    {
        if (m_LetterArray.Length <= 0)
        {
            Debug.LogError("画字母的笔画为0！");
            return;
        }

        for (int i = 0; i < m_LetterArray.Length; i++)
        {
            m_LetterArray[i].gameObject.SetActive(false);
            SetDefaultMaterial(m_LetterArray[i]);
        }

        m_DrawOrder = 0;
        DrawTarget(m_LetterArray[m_DrawOrder]);
    }

    private void DrawComplete()
    {
        Debug.Log("全部画完！");
        bIsDrawing = false;
        if (drawCompleteCallback != null)
        {
            drawCompleteCallback();
        }
    }

    private void OnClickHover()
    {
        if (!bIsDrawing) return;

        CheckNextMovePoint();

        CheckNextWayPointIndex();

        CheckDrawMask();

        CheckBrushMove();

    }

    private void DrawTarget(Transform target)
    {
        bIsDrawing = true;
        m_WayPointIndex = 0;
        target.gameObject.SetActive(true);

        SetDrawMaterial(target);
        DOTweenPath tweenPath = target.GetComponent<DOTweenPath>();
        m_WayPoints = tweenPath.wps.ToArray();

        m_Brush.position = m_CurrentPoint = m_PreviousPoint = m_WayPoints[0];
        m_Brush.rotation = Quaternion.LookRotation((m_WayPoints[1] - m_WayPoints[0]).normalized, m_Brush.up);

        //m_CurrentPoint = m_WayPoints[0];
        //m_PreviousPoint = m_CurrentPoint;
        m_Brush.DOPath(m_WayPoints, m_MoveDuration, PathType.CatmullRom, PathMode.Full3D).SetLookAt(0.001f);
        m_Brush.DOPause();
    }

    private void DrawNext()
    {
        m_Brush.DOKill();

        m_DrawOrder++;
        if (m_DrawOrder >= m_LetterArray.Length)
        {
            bIsDrawing = false;
            DrawComplete();
            return;
        }
        else
        {
            //Debug.Log("--------------: DrawNext");
            DrawTarget(m_LetterArray[m_DrawOrder]);
        }
    }

    private void DrawCurrentEnd()
    {
        foreach (GameObject go in m_DrawList)
        {
            go.SetActive(false);
        }

        m_MaskList.AddRange(m_DrawList.ToArray());
        m_DrawList.Clear();

        SetDefaultMaterial(m_LetterArray[m_DrawOrder]);

        DrawNext();
    }

    void CheckBrushMove()
    {
        if (Vector3.Distance(m_Brush.position, m_CurrentPoint) < 1)
        {
            m_Brush.DOPause();
            if (m_WayPointIndex >= m_WayPoints.Length - 1)
            {
                DrawCurrentEnd();
            }
        }
        else if (Vector3.Dot((m_CurrentPoint - m_Brush.position).normalized, (m_Brush.position - m_PreviousPoint).normalized) < 0)
        {
            m_Brush.DOPause();
        }
        else
        {
            m_Brush.DOPlay();
        }
    }

    void CheckNextMovePoint()
    {
        RaycastHit hit;
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100000))
        {
            if (m_WayPointIndex < m_WayPoints.Length - 1)
            {
                Vector3 startPoint = m_CurrentPoint;
                Vector3 endPoint = m_WayPoints[m_WayPointIndex + 1];

                Debug.DrawLine(startPoint, endPoint, Color.red);

                Vector3 moveDirection = endPoint - startPoint; // 移动方向向量
                Vector3 projectDirection = hit.point - startPoint; // 投射方向向量

                Debug.DrawLine(startPoint, hit.point, Color.red);

                if (Vector3.Dot(moveDirection.normalized, projectDirection.normalized) < 0)
                    return;
                Vector3 projectPoint = Vector3.Project(projectDirection, moveDirection.normalized) + startPoint; //投射点
                Debug.DrawLine(projectPoint, hit.point, Color.white);
                if (Vector3.Distance(projectPoint, startPoint) > moveDirection.magnitude + 1)
                    return;

                float projectDis = Vector3.Distance(projectPoint, hit.point);
                //Debug.Log(projectDis);
                if (projectDis < m_MaxProjectDis)
                {
                    if (Vector3.Distance(m_CurrentPoint, projectPoint) < m_NewPointMaxDis)
                        m_CurrentPoint = projectPoint;
                }
            }
            else
            {
                // 到达最后一个点
                m_CurrentPoint = m_WayPoints[m_WayPoints.Length - 1];
            }
        }
    }

    void CheckNextWayPointIndex()
    {
        if (m_WayPointIndex >= m_WayPoints.Length - 1)
            return;
        if (Vector3.Distance(m_CurrentPoint, m_WayPoints[m_WayPointIndex + 1]) < m_MinDis)
        {
            m_WayPointIndex++;
        }
    }

    void CheckDrawMask()
    {
        float dis = Vector3.Distance(m_Brush.position, m_PreviousPoint);
        if (dis > m_DrawMaskDis)
        {
            CreateMask();
            m_PreviousPoint = m_Brush.position;
        }
    }

    void CreateMask()
    {
        GameObject go = GameObject.Instantiate(m_DrawMask);
        go.transform.position = m_Brush.Find("Brush").position;
        go.transform.rotation = m_Brush.Find("Brush").rotation;
        if (m_DrawMaskParent != null)
        {
            go.transform.SetParent(m_DrawMaskParent.transform);
        }
        m_DrawList.Add(go);
    }


    private void SetDrawMaterial(Transform target)
    {
        target.GetComponent<Renderer>().material.shader = Shader.Find(downShader);
    }

    private void SetDefaultMaterial(Transform target)
    {
        target.GetComponent<Renderer>().material.shader = Shader.Find(defaultShader);
    }




}
